/************************************************************************
* @Copyright: 2023-2024
* @FileName:
* @Description: Open source mediasoup C++ controller library
* @Version: 1.0.0
* @Author: Jackie Ou
* @CreateTime: 2023-10-30
*************************************************************************/

#pragma once

#include <memory>
#include "stl/threadsafe_unordered_set.hpp"
#include <uv.h>
#include "interface/i_worker_controller.h"
#include "utils.h"
#include "FBS/request.h"
#include "FBS/response.h"
#include "FBS/message.h"
#include "FBS/notification.h"
#include "FBS/worker.h"
#include "FBS/transport.h"

namespace srv {
    
    struct WorkerSettings
    {
        /**
         * Logging level for logs generated by the media worker subprocesses (check
         * the Debugging documentation). Valid values are 'debug', 'warn', 'error' and
         * 'none'. Default 'error'.
         */
        std::string logLevel = "debug";
        
        /**
         * Log tags for debugging. Check the meaning of each available tag in the
         * Debugging documentation.
         *  options: 'info' | 'ice' | 'dtls' | 'rtp' | 'srtp' | 'rtcp' | 'rtx' | 'bwe' | 'score' | 'simulcast' | 'svc' | 'sctp' | 'message';
         */
        std::vector<std::string> logTags;
        
        /**
         * Minimun RTC port for ICE, DTLS, RTP, etc. Default 10000.
         */
        int32_t rtcMinPort = 10000;
        
        /**
         * Maximum RTC port for ICE, DTLS, RTP, etc. Default 59999.
         */
        int32_t rtcMaxPort = 59999;
        
        /**
         * Path to the DTLS public certificate file in PEM format. If unset, a
         * certificate is dynamically created.
         */
        std::string dtlsCertificateFile;
        
        /**
         * Path to the DTLS certificate private key file in PEM format. If unset, a
         * certificate is dynamically created.
         */
        std::string dtlsPrivateKeyFile;
        
        /**
         * Field trials for libwebrtc.
         * @private
         *
         * NOTE: For advanced users only. An invalid value will make the worker crash.
         * Default value is
         * "WebRTC-Bwe-AlrLimitedBackoff/Enabled/".
         */
        std::string libwebrtcFieldTrials;
        
        /**
         * Custom application data.
         */
        Json appData;
    };
    
    void to_json(Json& j, const WorkerSettings& st);
    void from_json(const Json& j, WorkerSettings& st);
    
    class Channel;

    class WorkerController : public IWorkerController, public std::enable_shared_from_this<WorkerController>
    {
    public:
        WorkerController(const std::shared_ptr<WorkerSettings>& settings);
        
        ~WorkerController();
        
        void init() override;
        
        void destroy() override;
        
        void runWorker() override;
        
        int pid() override { return _process.pid; }
        
        void close() override;

        bool closed() override;
        
        void setAppData(const Json& data) override { _appData = data; }
        
        std::shared_ptr<IWebRtcServerController> webRtcServerController() override;
        
        const Json& appData() override { return _appData; }
        
        std::shared_ptr<WorkerDump> dump() override;
        
        std::shared_ptr<WorkerResourceUsage> getResourceUsage() override;
        
        void updateSettings(const std::string& logLevel, const std::vector<std::string>& logTags) override;
        
        std::shared_ptr<IWebRtcServerController> createWebRtcServerController(const std::shared_ptr<WebRtcServerOptions>& options, const Json& appData) override;
        
        std::shared_ptr<IRouterController> createRouterController(const std::vector<RtpCodecCapability>& mediaCodecs, const Json& appData) override;

    private:
        std::vector<std::string> getArgs(const std::shared_ptr<WorkerSettings>& settings);
        
        void onWebRtcServerClose(std::shared_ptr<IWebRtcServerController> controller);
        
        void onRouterClose(std::shared_ptr<IRouterController> controller);
        
    private:
        void handleWorkerNotifications();
        
        void onChannel(const std::string& targetId, FBS::Notification::Event event, const std::vector<uint8_t>& data);
    
    private:
        std::shared_ptr<WorkerSettings> _settings;
        
        // Channel instance.
        std::shared_ptr<Channel> _channel;

        // Closed flag.
        std::atomic_bool _closed { false };

        // Custom app data.
        Json _appData;

        // WebRtcServers set.
        std::threadsafe_unordered_set<std::shared_ptr<IWebRtcServerController>> _webRtcServerControllers;

        // Routers set.
        std::threadsafe_unordered_set<std::shared_ptr<IRouterController>> _routerControllers;
        
        uv_process_t _process;
        
        Loop _loop;
    };
    
    std::shared_ptr<WorkerDump> parseWorkerDumpResponse(const FBS::Worker::DumpResponse* response);
}
